package web.error;

import framework.config.ErrorConfig;
import framework.exceptions.*;
import framework.utils.RequestUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Controller
public class SysErrorController implements ErrorController {

    private ErrorConfig errorConfig;
    private ErrorAttributes errorAttributes;

    public static final String ERROR_PATH = "/error";

    public SysErrorController(ErrorAttributes errorAttributes, ErrorConfig errorConfig) {
        this.errorAttributes = errorAttributes;
        this.errorConfig = errorConfig;
        this.initTemplates(errorConfig);
    }

    private void initTemplates(ErrorConfig errorConfig) {

        if (!errorConfig.getOutputJson()) {
            Map<String, Object> map = new HashMap<>();
            map.put("200", ClassLoader.getSystemResource("templates/error/200.html"));
            map.put("400", ClassLoader.getSystemResource("templates/error/400.html"));
            map.put("401", ClassLoader.getSystemResource("templates/error/401.html"));
            map.put("403", ClassLoader.getSystemResource("templates/error/403.html"));
            map.put("404", ClassLoader.getSystemResource("templates/error/404.html"));
            map.put("405", ClassLoader.getSystemResource("templates/error/405.html"));
            map.put("500", ClassLoader.getSystemResource("templates/error/500.html"));

            //check
            List<String> noFounds = new ArrayList<>();
            for (String k : map.keySet()) {
                if (map.get(k) == null) {
                    noFounds.add(k + ".html");
                }
            }

            //
            if (noFounds.size() > 0) {
                errorConfig.setOutputJson(true);
                log.warn("your not enable runtime.error.output-json, but force set to enable because no config templates/error/" + String.join(",", noFounds));
            }
        }
    }

    /**
     * 页面
     */
    @RequestMapping(value = ERROR_PATH)
    public ModelAndView errorDisposer(HttpServletRequest request, HttpServletResponse response, WebRequest webRequest) throws IOException {
        return this.errorRequest(request, response, webRequest);
    }

//    /**
//     * html
//     *
//     * @param request
//     * @param response
//     * @return
//     */
//    @RequestMapping(value = "/error", produces = {"text/html"})
//    public String errorHtml(HttpServletRequest request, HttpServletResponse response, WebRequest webRequest, Model model) throws IOException {
//        // Throwable e = (Throwable) request.getAttribute("javax.servlet.error.exception");
//        return this.errorDisposer(request,response,webRequest,model);
//    }

    private ModelAndView errorRequest(HttpServletRequest request, HttpServletResponse response, WebRequest webRequest) throws IOException {
        Throwable error = this.errorAttributes.getError(webRequest);
        if (error == null) {
            int code = response.getStatus();
            if (404 == code) {
                error = new Error404Exception(RequestUtil.getMessageDefault("error.e404", "Not found"));
            } else if (405 == code) {
                error = new Error405Exception(RequestUtil.getMessageDefault("error.e405", "No Access"));
            } else if (403 == code) {
                error = new Error403Exception(RequestUtil.getMessageDefault("error.e403", "Forbidden"));
            } else if (401 == code) {
                error = new Error401Exception(RequestUtil.getMessageDefault("error.e401", "Unauthorized"));
            } else if (400 == code) {
                error = new Error400Exception(RequestUtil.getMessageDefault("error.e400", "Bad Request"));
            } else {
                error = new WebException(RequestUtil.getMessageDefault("error.e500", "Server error"));
            }
        }
        return SysErrorHandler.handleException(this.errorConfig, error, request, response);
    }
}
